package com.blue.Impl.workflow;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.blue.common.constant.CommonConstant;
import com.blue.common.exception.CustomException;
import com.blue.common.utils.ConvertUtils;
import com.blue.dto.workflow.BusinessFieldDTO;
import com.blue.dto.workflow.DefinitionDTO;
import com.blue.dto.workflow.NodeConditionDTO;
import com.blue.dto.workflow.NodeDTO;
import com.blue.po.workflow.BusinessFieldPO;
import com.blue.po.workflow.NodeConditionPO;
import com.blue.po.workflow.NodePO;
import com.blue.service.workflow.IBusinessFieldService;
import com.blue.service.workflow.INodeConditionService;
import com.blue.service.workflow.INodeService;
import com.blue.vo.workflow.DefinitionVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.blue.mapper.workflow.DefinitionMapper;
import com.blue.po.workflow.DefinitionPO;
import com.blue.service.workflow.IDefinitionService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


@Service
public class DefinitionServiceImpl extends ServiceImpl<DefinitionMapper, DefinitionPO> implements IDefinitionService {

    @Autowired
    private IBusinessFieldService businessFieldService;
    @Autowired
    private INodeService nodeService;
    @Autowired
    private INodeConditionService nodeConditionService;

    @Transactional
    @Override
    public void add(DefinitionDTO requestDTO) {
        //保存基本信息
        requestDTO.setWfNo(generateWfNo());
        String confJSON = JSON.toJSONString(requestDTO);
        DefinitionPO definitionPO = ConvertUtils.convert(DefinitionPO.class, requestDTO);
        definitionPO.setEnableFlag(CommonConstant.YES);
        definitionPO.setVersion(getVersion(null));
        definitionPO.setConfJson(confJSON);
        this.save(definitionPO);
        //保存业务字段信息
        saveBusinessField(requestDTO, definitionPO.getId());
        //保存节点信息
        saveNode(requestDTO, definitionPO.getId());
        this.updateById(definitionPO);

    }

    /**
     * 生成流程编码
     *
     * @return
     */
    private String generateWfNo() {
        StringBuilder builder = new StringBuilder();
        builder.append("WF-");
        String date = new SimpleDateFormat("yyMMdd").format(new Date());
        builder.append(date);
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            builder.append(random.nextInt(10));
        }
        return builder.toString();
    }

    /**
     * 获取版本号
     *
     * @param wfNo
     * @return
     */
    private BigDecimal getVersion(String wfNo) {
        if (StringUtils.isBlank(wfNo)) {
            return BigDecimal.valueOf(1.0);
        }
        BigDecimal version = baseMapper.getMaxVersion(wfNo);
        if (version == null) {
            return BigDecimal.valueOf(1.0);
        }
        version = version.add(BigDecimal.valueOf(0.1));
        return version;
    }

    /**
     * 保存业务字段
     *
     * @param requestDTO
     * @param definitionId
     */
    private void saveBusinessField(DefinitionDTO requestDTO, String definitionId) {
        List<BusinessFieldDTO> businessFieldList = requestDTO.getBusinessFieldList();
        if (CollectionUtils.isEmpty(businessFieldList)) {
            throw new CustomException("流程业务字段配置不能为空！");
        }
        List<BusinessFieldPO> List = new ArrayList<>();
        List<BusinessFieldPO> businessFieldPOS = ConvertUtils.convertList(BusinessFieldPO.class, businessFieldList);
        businessFieldPOS.forEach(item -> item.setDefinitionId(definitionId));
        businessFieldService.saveBatch(businessFieldPOS);
        businessFieldPOS.forEach(businessFieldPO -> {
            List<BusinessFieldPO> tableFields = businessFieldPO.getTableFields();
            if (!CollectionUtils.isEmpty(tableFields)) {
                tableFields.forEach(tableField -> {
                    tableField.setDefinitionId(definitionId);
                    tableField.setFieldId(businessFieldPO.getId());
                });
                List.addAll(tableFields);
            }
        });
        businessFieldService.saveBatch(List);
    }

    /**
     * 保存节点
     *
     * @param requestDTO
     * @param definitionId
     */
    private void saveNode(DefinitionDTO requestDTO, String definitionId) {
        NodeDTO node = requestDTO.getNode();
        if (node == null || node.getChildNode() == null) {
            throw new CustomException("节点信息为空！");
        }
        List<NodeDTO> Nodes = new ArrayList<>();
        List<NodeConditionDTO> nodeConditions = new ArrayList<>();
        analyzeOutNode(Nodes, nodeConditions, node, definitionId);
        if (!CollectionUtils.isEmpty(nodeConditions)) {
            List<NodeConditionPO> nodeConditionPOS = ConvertUtils.convertList(NodeConditionPO.class, nodeConditions);
            nodeConditionService.saveBatch(nodeConditionPOS);
        }
        if (!CollectionUtils.isEmpty(Nodes)) {
            List<NodePO> nodePOS = ConvertUtils.convertList(NodePO.class, Nodes);
            nodeService.saveBatch(nodePOS);
        }
    }

    /**
     * 解析最外层节点
     *
     * @param Nodes
     * @param nodeConditions
     * @param node
     * @param definitionId
     */
    private void analyzeOutNode(List<NodeDTO> Nodes, List<NodeConditionDTO> nodeConditions,
                                NodeDTO node, String definitionId) {
        String nodeId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 19);
        node.setId(nodeId);
        node.setDefinitionId(definitionId);
        Nodes.add(node);
        List<NodeDTO> conditionNodes = node.getConditionNodes();
        NodeDTO childNode = node.getChildNode();
        if (!CollectionUtils.isEmpty(conditionNodes)) {
            analyzeConditionNode(Nodes, nodeConditions, conditionNodes, definitionId, nodeId, nodeId, childNode == null);
        }
        if (childNode == null) {
            //子节点为空并节点类型为审批节点则表示该节点为结束节点
            if (CommonConstant.APPROVE_NODE.equals(node.getNodeType())) {
                node.setNodeType(CommonConstant.END_NODE);
            }
            return;
        }
        childNode.setDefinitionId(definitionId);
        childNode.setParentNodeId(nodeId);
        analyzeOutNode(Nodes, nodeConditions, childNode, definitionId);
    }

    /**
     * 接下条件节点
     *
     * @param Nodes
     * @param nodeConditions
     * @param conditionNodes
     * @param definitionId
     * @param parentNodeId
     * @param outNodeId
     * @param endNodeFlag
     */
    private void analyzeConditionNode(List<NodeDTO> Nodes, List<NodeConditionDTO> nodeConditions,
                                      List<NodeDTO> conditionNodes, String definitionId,
                                      String parentNodeId, String outNodeId, boolean endNodeFlag) {
        for (NodeDTO conditionNode : conditionNodes) {
            String nodeId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 19);
            conditionNode.setId(nodeId);
            conditionNode.setDefinitionId(definitionId);
            conditionNode.setParentNodeId(parentNodeId);
            conditionNode.setOutNodeId(outNodeId);
            Nodes.add(conditionNode);
            NodeDTO childNode = conditionNode.getChildNode();
            List<NodeConditionDTO> nodeConditionDTOS = conditionNode.getNodeConditions();
            if (CollectionUtils.isEmpty(nodeConditionDTOS)) {
                throw new CustomException(conditionNode.getNodeNm() + "条件节点的条件不能为空！");
            }
            nodeConditionDTOS.forEach(item -> item.setNodeId(nodeId));
            nodeConditions.addAll(nodeConditionDTOS);
            List<NodeDTO> CondNodes = conditionNode.getConditionNodes();
            if (!CollectionUtils.isEmpty(CondNodes)) {
                throw new CustomException("条件节点子节点必须为审批节点！");
            }
            if (childNode == null) {
                throw new CustomException("条件节点子节点不能为空！");
            }
            analyzeNode(Nodes, nodeConditions, childNode, definitionId, nodeId, outNodeId, endNodeFlag);
        }
    }

    /**
     * 解析内部非条件节点
     *
     * @param Nodes
     * @param nodeConditions
     * @param node
     * @param definitionId
     * @param parentNodeId
     * @param outNodeId
     * @param endNodeFlag
     */
    private void analyzeNode(List<NodeDTO> Nodes, List<NodeConditionDTO> nodeConditions,
                             NodeDTO node, String definitionId, String parentNodeId,
                             String outNodeId, boolean endNodeFlag) {
        String nodeId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 19);
        node.setId(nodeId);
        node.setDefinitionId(definitionId);
        node.setParentNodeId(parentNodeId);
        node.setOutNodeId(outNodeId);
        Nodes.add(node);
        List<NodeDTO> conditionNodes = node.getConditionNodes();
        NodeDTO childNode = node.getChildNode();
        if (!CollectionUtils.isEmpty(conditionNodes)) {
            analyzeConditionNode(Nodes, nodeConditions, conditionNodes, definitionId, nodeId, outNodeId, endNodeFlag);
        }
        if (childNode == null) {
            if (endNodeFlag) {
                node.setNodeType(CommonConstant.END_NODE);
            }
            return;
        }
        analyzeNode(Nodes, nodeConditions, childNode, definitionId, nodeId, outNodeId, endNodeFlag);
    }

    @Transactional
    @Override
    public void edit(DefinitionDTO requestDTO) {
        //将上版本流程定义设置为未启用
        this.update(new LambdaUpdateWrapper<DefinitionPO>()
                .set(DefinitionPO::getEnableFlag, CommonConstant.NO)
                .eq(DefinitionPO::getWfNo, requestDTO.getWfNo())
                .eq(DefinitionPO::getEnableFlag, CommonConstant.YES));
        //保存新版本流程定义
        DefinitionPO definitionPO = ConvertUtils.convert(DefinitionPO.class, requestDTO);
        definitionPO.setVersion(getVersion(requestDTO.getWfNo()));
        definitionPO.setEnableFlag(CommonConstant.YES);
        String confJson = JSON.toJSONString(requestDTO);
        definitionPO.setConfJson(confJson);
        this.save(definitionPO);
        //保存业务字段配置
        saveBusinessField(requestDTO, definitionPO.getId());
        //保存节点配置
        saveNode(requestDTO, definitionPO.getId());
    }

    @Override
    public DefinitionVO queryById(String id) {
        DefinitionPO definitionPO = this.getById(id);
        String confJson = definitionPO.getConfJson();
        return JSON.parseObject(confJson, DefinitionVO.class);
    }

    @Override
    @Transactional
    public void enable(DefinitionDTO requestDTO) {
        DefinitionPO definitionPO = this.getOne(new LambdaQueryWrapper<DefinitionPO>()
                .select(DefinitionPO::getId, DefinitionPO::getWfNo)
                .eq(DefinitionPO::getId, requestDTO.getId()));
        if (definitionPO == null) {
            throw new CustomException("流程定义不存在！");
        }
        //将原启用流程更新为未启用
        this.update(new LambdaUpdateWrapper<DefinitionPO>()
                .set(DefinitionPO::getEnableFlag, CommonConstant.NO)
                .eq(DefinitionPO::getWfNo, definitionPO.getWfNo())
                .eq(DefinitionPO::getEnableFlag, CommonConstant.YES));
        //更新当前流程为启用状态
        definitionPO.setEnableFlag(CommonConstant.YES);
        this.updateById(definitionPO);
    }
}
